using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Sirenix.Serialization;
using UnityEngine;
using static cmd.LevelLayerData;

namespace cmd
{
    [AssetList]
    public class RandomItemGenerateDataSO : SerializedScriptableObject
    {
        [field: OdinSerialize]
        [field: HideLabel]
        public RandomItemGenerateData RandomItemGenerateData { get; set; } = new(new());
    }

    [Serializable]
    public readonly struct RandomItemGenerateData
    {
        public RandomItemGenerateData(
            // int randomItemCount = 1,
            List<PickableItemInRandomWeightConfiguration> randomItemConfigList = null
        )
        {
            // RandomItemCount = randomItemCount;
            RandomItemConfigList = randomItemConfigList ?? new();
        }

        // [field: SerializeField]
        // [field: LabelText("随机生成可拾取物品的数量")]
        // public int RandomItemCount { get; init; }

        [field: OdinSerialize, Space(10)]
        [field: ListDrawerSettings(
            ShowIndexLabels = true,
            NumberOfItemsPerPage = 5,
            CustomAddFunction = nameof(CustomAddRandomFunction)
        )]
        [field: LabelText("随机生成可拾取物品的配置列表")]
        public List<PickableItemInRandomWeightConfiguration> RandomItemConfigList { get; init; }

        private PickableItemInRandomWeightConfiguration CustomAddRandomFunction() =>
            (
                1,
                new(
                    configMethod: PickableItemInLevelConfiguration
                        .PickableItemInLevelConfigMethod
                        .UseSOComplete
                )
            );

        /// <summary>
        /// 根据权重和数量抽选出随机生成物品
        /// </summary>
        /// <returns>随机生成的物品配置列表</returns>
        public List<PickableItemInLevelConfiguration> GenerateRandomItems(int randomItemCount = 1)
        {
            if (randomItemCount <= 0 || RandomItemConfigList.Count == 0)
                return new();

            // 计算总权重
            float totalWeight = RandomItemConfigList.Sum(x => x.Weight);
            if (totalWeight <= 0)
                return new();

            // 构建权重范围表
            var weightRanges =
                new List<(float Start, float End, PickableItemInLevelConfiguration Config)>();
            float currentWeight = 0;
            foreach (var (weight, config) in RandomItemConfigList)
            {
                weightRanges.Add((currentWeight, currentWeight + weight, config));
                currentWeight += weight;
            }

            var result = new List<PickableItemInLevelConfiguration>();
            // 根据权重随机抽取指定数量的物品
            for (int i = 0; i < randomItemCount; i++)
            {
                float randomValue = UnityEngine.Random.Range(0f, totalWeight);

                // 二分查找对应的权重区间
                int left = 0;
                int right = weightRanges.Count - 1;
                while (left <= right)
                {
                    int mid = (left + right) / 2;
                    var (start, end, config) = weightRanges[mid];

                    if (randomValue >= start && randomValue < end)
                    {
                        result.Add(config);
                        break;
                    }

                    if (randomValue < start)
                        right = mid - 1;
                    else
                        left = mid + 1;
                }
            }

            return result;
        }
    }

    [Serializable, HideLabel]
    public readonly struct PickableItemInRandomWeightConfiguration
    {
        [field: SerializeField]
        public float Weight { get; init; }

        [field: SerializeField]
        public PickableItemInLevelConfiguration Config { get; init; }

        public PickableItemInRandomWeightConfiguration(
            float weight,
            PickableItemInLevelConfiguration config
        )
        {
            Weight = weight;
            Config = config;
        }

        public override bool Equals(object obj) =>
            obj is PickableItemInRandomWeightConfiguration other
            && Weight == other.Weight
            && EqualityComparer<PickableItemInLevelConfiguration>.Default.Equals(
                Config,
                other.Config
            );

        public override int GetHashCode() => HashCode.Combine(Weight, Config);

        public void Deconstruct(out float weight, out PickableItemInLevelConfiguration config)
        {
            weight = Weight;
            config = Config;
        }

        public static implicit operator (float Weight, PickableItemInLevelConfiguration Config)(
            PickableItemInRandomWeightConfiguration value
        ) => (value.Weight, value.Config);

        public static implicit operator PickableItemInRandomWeightConfiguration(
            (float Weight, PickableItemInLevelConfiguration Config) value
        ) => new(value.Weight, value.Config);
    }
}
